#ifndef SURFACEMANAGER_H
#define SURFACEMANAGER_H

#include "surface.h"

#include <map>
#include <string>
#include <vector>
#include <list>

using namespace std; 


typedef enum
{
    NoFlip = 0,
    VerticalFlip = 1,
    HorizontalFlip = 2
} FlipOption;

/**
 * This singleton class manages surfaces and allows you to only need to specify
 * a name to get the corresponding Surface.
 */
class SurfaceManager
{
    public:
        /**
         * Destructor of the SurfaceManager. Deletes all the surfaces.
         */
        ~SurfaceManager();
        
        /**
         * Pointer to the only instance of this class (as this is a singleton).
         */
        static SurfaceManager& self();
        static bool exists();

        bool init();
        void update();
        void shutdown();
        
        /**
         * Given the name of a surface, it looks for the corresponding image file
         * in the filesystem inside the images directory using the 
         * ResourceManager, and then creates a Surface object in memory with
         * that image and stores it internally.
         * 
         * When flipped argument is HorizontalFlip, will also store internally a
         * flipped image with its name ending with "-right" if it was instead.
         * 
         * When flipped is VerticalFlip, same happens but with "-up" and "-down".
         * 
         * If the image is not found in the filesystem, it will try to find a
         * flipped image (either vertically or horizontally) and then flip it.
         * 
         * @return If the image is not found in filesystem nor flipped, returns
         * -1, otherwise if no error is found it returns 0.
         *
         * @param   name    The name of the surface
         * @param   flipped If flipped is different from NoFlip, it will also load
         *                  internally a flipped image (horizontally and/or
         *                  vertically flipped).
         */
        int loadSurface(const string& name, const FlipOption& flipped = NoFlip);
        
        /**
         * Loads all the images of a sprite as surface. This will be done adding
         * a number to the end of the name and trying to find if that image 
         * exists. That number will start from 0 upwards.
         * 
         * The numbering will be added with a '-' at the end of the name, For
         * example if name  was "nico-left", this function will call to 
         * loadSurface() with name being "nico-left-0", "nico-left-1", until
         * loadSurface() fails loading the images.
         * 
         * If no surface is found and the number is 0, it will try to load the
         * image without a numbering.
         * 
         * @return the number of surfaces this sprite contains or -1 if fails.
         * 
         * See the behaviour of @ref loadSurface().
         *
         */
        int loadSpriteSurfaces(const string& name);
        
        /**
         * Returns wether the given surface name is loaded internally or not.
         */
        bool hasSurface(const string& name);
        
        /**
         * Returns the surface associated with that name if it's been loaded
         * previously, or 0 if it's not found.
         */
        Surface* getSurface(const string& name);
        
        /**
         * Removes and deletes from memory the surface associated with a given
         * name if it's found. See @ref loadSurface() for details of how 
         * the parameters of this function work.
         */
        void removeSurface(const string& name, const FlipOption& flipped = NoFlip);
        
        
        /**
         * Removes and deletes from memory the surfaces associated with a given
         * name of a sprite. See @ref loadSpriteSurfaces() for details of how 
         * the parameters of this function work.
         */
        void removeSpriteSurfaces(const string& name, const FlipOption& flipped = NoFlip);
        
        /**
         * Returns the surface associated with that name if it's been loaded
         * previously, or 0 if it's not found.
         */
        Surface* operator[](const string& name);
        
    protected:
        /**
         * Protected constructor of the class. Doesn't do much really.
         */
        SurfaceManager();
        
        // Singleton pointer to the only instance of this class.
        static SurfaceManager* m_self;
        
        // Image suffix. Nomally it's just ".png"
        static string m_imageSuffix;
        
        // Contains all the surfaces associated with their names.
        map<string, Surface*> m_surfaces;
};

#endif
